{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Code for HW2, Problem 3\n",
    "\n",
    "Here, we use a slightly modified version of the code in `./Module_2.ipynb` to calculate the efficient frontier curve. To parametrize the curve, we construct a portfolio out of 5 stocks, and calculate the optimal weights for each value of standard deviation of the portfolio. So our constrained optimization problem becomes the following:\n",
    "\n",
    "Maximize $\\mathcal{L} = \\sum_i w_i E[r_i]$, subject to $\\sum_i w_i = 1$ and $\\sum_{ij} w_iw_j\\sigma_{ij} = \\sigma_p$, where $\\sigma_p$ is pre-provided. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import scipy.stats as stats\n",
    "import pandas as pd\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_csv(\"../data/2_Stock_Prices.csv\", index_col=0, parse_dates=True)\n",
    "# Clean/transform the data\n",
    "df = df.dropna(axis=1)\n",
    "df = df.apply(np.log)\n",
    "# Get the dataframe with daily returns\n",
    "returns_df = df.diff().dropna(axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.optimize import minimize\n",
    "\n",
    "# Compute the return of the portfolio, the volatility, and the Sharpe Ratio\n",
    "def get_ret_vol_sr(weights, means, cov, rf=0.05):\n",
    "    weights = np.array(weights)\n",
    "    # The means you enter are daily expected returns, so annualize them.\n",
    "    ret = np.sum(means*weights*252)\n",
    "    # The volatility is w*Sigma*w\n",
    "    vol = np.sqrt(np.dot(weights.T, np.dot(cov, weights)))\n",
    "\n",
    "    sr = (ret-rf)/vol\n",
    "\n",
    "    return np.array([ret, vol, sr])\n",
    "\n",
    "def find_weights(means, cov, std, rf=0.05):\n",
    "    '''For a fixed value of portfolio standard deviation, std, \n",
    "       find the optimal set of weights that maximizes the expected return.'''\n",
    "    \n",
    "    # Compute the return of the portfolio, the volatility, and the Sharpe Ratio\n",
    "    def get_ret_vol_sr(weights):\n",
    "        weights = np.array(weights)\n",
    "        # The means you enter are daily expected returns, so annualize them.\n",
    "        ret = np.sum(means*weights*252)\n",
    "        # The volatility is w*Sigma*w\n",
    "        vol = np.sqrt(np.dot(weights.T, np.dot(cov, weights)))\n",
    "\n",
    "        sr = (ret-rf)/vol\n",
    "\n",
    "        return np.array([ret, vol, sr])    \n",
    "          \n",
    "    # We want to maximize the Sharpe Ratio, ergo minimize the negative Sharpe Ratio.\n",
    "    def neg_sharpe(weights):\n",
    "        return -get_ret_vol_sr(weights)[2]\n",
    "\n",
    "    # Function for the constraints: We want to invest all of our money, nothing more, nothing less.\n",
    "    def check_sum(weights):\n",
    "        # Return 0 if sum of the weights is 1\n",
    "        return np.sum(weights)-1\n",
    "    \n",
    "    def fix_vol(weights, std):\n",
    "        '''Constraint on the portfolio uncertainty.'''\n",
    "        return get_ret_vol_sr(weights)[1] - std\n",
    "    \n",
    "    # Set the constraint: Weights need to sum to 1.\n",
    "    cons = ({\"type\":\"eq\", \"fun\":check_sum}, {\"type\":\"eq\", \"fun\":fix_vol, \"args\":[std]})\n",
    "    # Each stock should have some weight between 0 and 100% in our portfolio.\n",
    "    bounds = tuple([(0,1) for _ in range(len(means))])\n",
    "    \n",
    "    # Our initial guess is equally spreading the money.\n",
    "    init_guess = [1./len(means) for _ in range(len(means))]\n",
    "    \n",
    "    # Optimize!\n",
    "    opt_results = minimize(neg_sharpe, init_guess, method=\"SLSQP\", bounds=bounds, constraints=cons)\n",
    "    \n",
    "    return opt_results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 142,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.010210438748849854\n",
      "0.010250000075942255\n",
      "0.010500000886611743\n",
      "0.010750004377309464\n",
      "0.011000000509737875\n",
      "0.011250000401458925\n",
      "0.011500000253805688\n",
      "0.011750000501260746\n",
      "0.012000001372065567\n",
      "0.012250000197041661\n",
      "0.012500000976630975\n",
      "0.012750000296076813\n",
      "0.0130000002766025\n",
      "0.013250000039177165\n",
      "0.013500001604646563\n",
      "0.013750002036902296\n",
      "0.014000000473353109\n",
      "0.014250000338450529\n",
      "0.014500000798177147\n",
      "0.014750000049335061\n"
     ]
    }
   ],
   "source": [
    "# Choose 5 stocks\n",
    "my_df = returns_df.loc[:, ['AAPL', 'JPM', 'EBAY', 'NFLX', 'ORCL']]\n",
    "# Expected return of each individual stock\n",
    "means = np.array([0.065/252, 0.07/252, 0.08/252, 0.075/252, 0.06/252])\n",
    "# Covariance estimated from S&P 500 data\n",
    "cov = my_df.cov()\n",
    "\n",
    "#std=np.linspace(0.001,0.015)\n",
    "std = np.arange(10,15,0.25)*0.001\n",
    "# For each standard deviation (combined)\n",
    "# run the optimizer to find the optimal weights\n",
    "# and using the optimal weights, get the exp. return\n",
    "returns = np.zeros_like(std)\n",
    "vols = np.zeros_like(std)\n",
    "sharpe_ratios = np.zeros_like(std)\n",
    "weight_list = []\n",
    "for idx, dev in enumerate(std):\n",
    "    # Run the optimizer\n",
    "    opt = find_weights(means, cov, dev, rf=0.02)\n",
    "    # If you output opt, you get a bunch of info, and in \"x\", the weights are stored.\n",
    "    weights = opt[\"x\"]\n",
    "    weight_list.append(weights)\n",
    "    # Get the expected return out of the portfolio\n",
    "    # using the optimal weights\n",
    "    ret, vol, sr = get_ret_vol_sr(weights, means, cov)\n",
    "    returns[idx] = ret\n",
    "    print(vol)\n",
    "    vols[idx] = vol\n",
    "    sharpe_ratios[idx] = sr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the efficient frontier curve!\n",
    "fig, ax = plt.subplots(1,1)\n",
    "ax.plot(vols, returns)\n",
    "ax.set_xlabel('Portfolio Risk')\n",
    "ax.set_ylabel('Expected Yearly Return')\n",
    "ax.set_title('Efficient Frontier')\n",
    "ax.grid(True)\n",
    "fig.savefig('./output/eff_frontier.pdf')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Find Maximum Sharpe Ratio\n",
    "\n",
    "Here, we plot the Sharpe Ratios for each possible combination of stocks lying in Efficient Frontier curve, and find the optimal portfolio that maximizes the Sharpe Ratio.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Maximum return: 0.0754\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Find the maximum SR\n",
    "idx_max = np.argmax(sharpe_ratios)\n",
    "vol_max = vols[idx_max]\n",
    "ret_max = returns[idx_max]\n",
    "print(f'Maximum return: {ret_max:.4f}')\n",
    "\n",
    "fig, ax = plt.subplots(1,1)\n",
    "ax.plot(vols, sharpe_ratios, 'o')\n",
    "ax.plot([vol_max]*2, [1.6,2.2], 'r')\n",
    "ax.set_ylim(1.6, 2.2)\n",
    "ax.set_xlabel('Portfolio Risk')\n",
    "ax.set_ylabel('Sharpe Ratio')\n",
    "ax.grid(True)\n",
    "fig.savefig('./output/sr_risk_rf_002.pdf')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.62614296 1.7360727  1.89007573 1.95869734 2.00196577 2.03173503\n",
      " 2.0529503  2.06732607 2.07345549 2.07416969 2.07133687 2.06527017\n",
      " 2.05536597 2.04307434 2.0292784  2.01451597 1.99913822 1.9833853\n",
      " 1.96742693 1.95138597]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.012250000038908209"
      ]
     },
     "execution_count": 138,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(sharpe_ratios)\n",
    "vols[np.argmax(sharpe_ratios)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.62614296 1.7360727  1.89007573 1.95869734 2.00196577 2.03173503\n",
      " 2.0529503  2.06732607 2.07345549 2.07416969 2.07133687 2.06527017\n",
      " 2.05536597 2.04307434 2.0292784  2.01451597 1.99913822 1.9833853\n",
      " 1.96742693 1.95138597]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.012250000038908209"
      ]
     },
     "execution_count": 139,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(sharpe_ratios)\n",
    "vols[np.argmax(sharpe_ratios)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.03777829, 0.36230265, 0.51957498, 0.08034408, 0.        ])"
      ]
     },
     "execution_count": 140,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "weight_list[idx_max] # rf = 0.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 145,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([3.77660560e-02, 3.62320355e-01, 5.19568286e-01, 8.03453031e-02,\n",
       "       1.71337825e-17])"
      ]
     },
     "execution_count": 145,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "weight_list[idx_max] # rf = 0.02"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "weight_list[idx_max] # rf = 0.05"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
